package com.arpa.oms.service.impl;

import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.util.StrUtil;
import com.arpa.ntocc.common.common.exception.ServiceException;
import com.arpa.ntocc.common.common.util.CommonUtil;
import com.arpa.oms.domain.dto.OmsInventoryDTO;
import com.arpa.oms.domain.entity.OmsInventory;
import com.arpa.oms.domain.vo.OmsInventoryVO;
import com.arpa.oms.mapper.OmsInventoryMapper;
import com.arpa.oms.service.IOmsInventoryService;
import com.arpa.wms.cache.WarehouseCache;
import com.arpa.wms.domain.consts.NumConst;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;


/**
 * <p>
 * OMS采购单明细 服务实现类
 * </p>
 *
 * @author LEO
 * @since 2020-10-22
 */
@Service()
public class OmsInventoryServiceImpl extends ServiceImpl<OmsInventoryMapper, OmsInventory> implements IOmsInventoryService {
    private final WarehouseCache warehouseCache;

    public OmsInventoryServiceImpl(WarehouseCache warehouseCache) {
        this.warehouseCache = warehouseCache;
    }

    /**
     * 从库存中获取相同库存，如果没有则返回空
     *
     * @param goodsCode
     * @param warehouseCode
     * @param shipmentCode
     * @return
     */
    @Override
    public OmsInventory hasSameInventory(String goodsCode, String warehouseCode, String shipmentCode) {
        OmsInventory inventory = null;
        // 为避免出现查出多条错误，使用list做结果集，取第一条作为操作数据
        List<OmsInventory> inventories = this.list(new QueryWrapper<OmsInventory>().lambda().eq(OmsInventory::getGoodsCode, goodsCode)
                .eq(OmsInventory::getWarehouseCode, warehouseCode).eq(OmsInventory::getShipmentCode, shipmentCode));
        if (IterUtil.isNotEmpty(inventories)) {
            inventory = inventories.get(NumConst.NUM_ZERO);
        }
        return inventory;
    }

    /**
     * 调整库存数量，正数为加库存，负数为减库存
     *
     * @param code
     * @param adjustQuantity
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void adjustQuantity(String code, BigDecimal adjustQuantity) {
        boolean actionFlag = this.update(new UpdateWrapper<OmsInventory>().lambda().eq(OmsInventory::getCode, code)
                        .setSql(" quantity = quantity + " + adjustQuantity)
                        .apply(" quantity + " + adjustQuantity + " >= 0"));
        if (!actionFlag) {
            throw new ServiceException(" 操作后库存小于0，无法操作");
        }
    }

    /**
     * 调整库存数量（和价格），正数为加库存（和价格），负数为减库存（和价格）
     *
     * @param code
     * @param adjustQuantity
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void adjustQuantityAndPrice(String code, BigDecimal adjustQuantity) {
        boolean actionFlag = this.update(new UpdateWrapper<OmsInventory>().lambda().eq(OmsInventory::getCode, code)
                        .setSql(" quantity = quantity + " + adjustQuantity)
                        .setSql("total_amount = average_unit_price * quantity")
                        .apply(" quantity + " + adjustQuantity + " >= 0"));
        if (!actionFlag) {
            throw new ServiceException(" 操作后库存小于0，无法操作");
        }
    }


    /**
     * 调整库占用库存数量，正数为加，负数为减
     * @param code
     * @param adjustQuantity
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void adjustUseQuantity(String code, BigDecimal adjustQuantity) {
        this.update(new UpdateWrapper<OmsInventory>().lambda().eq(OmsInventory::getCode, code)
                .setSql(" use_quantity = use_quantity + " + adjustQuantity));
    }

    /**
     * 锁可用库存
     * 库存表中占用数量增加，如果最终的可用数量<0的话，则报错，回滚
     * @param warehouseCode
     * @param goodsCode
     * @param goodsName
     * @param shipmentCode
     * @param lockQuantity
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void lockUsefulInventory(String warehouseCode, String goodsCode, String goodsName, String shipmentCode, BigDecimal lockQuantity) {
        // 增加占用数量， 数量条件是 总数量 >= 原占用数量 + 不可用数量 + 新占用数量
        boolean updateFlag = this.update(new UpdateWrapper<OmsInventory>().lambda().eq(OmsInventory::getWarehouseCode, warehouseCode)
                    .eq(OmsInventory::getGoodsCode, goodsCode).eq(OmsInventory::getShipmentCode, shipmentCode)
                    .apply(" quantity >= use_quantity + cont_use_quantity + " + lockQuantity)
                    .setSql(" use_quantity = use_quantity + " + lockQuantity));
        if(!updateFlag){
            throw new ServiceException("商品“" + goodsName + "”可用库存不足。");
        }
    }

    /**
     * 更新oms的不可用库存数量，用于wms各种库存变动操作后，同步oms的不可用库存数量
     * @param warehouseCode
     * @param goodsCode
     * @param shipmentCode
     * @param contUseQuantity
     */
    @Override
    public void refreshOmsContUseQuantity(String warehouseCode, String shipmentCode, String goodsCode, BigDecimal contUseQuantity) {
        this.update(new UpdateWrapper<OmsInventory>().lambda().eq(OmsInventory::getWarehouseCode, warehouseCode)
                .eq(OmsInventory::getShipmentCode, shipmentCode).eq(OmsInventory::getGoodsCode, goodsCode)
                .set(OmsInventory::getContUseQuantity, contUseQuantity));
    }


    @Override
    public OmsInventoryVO queryListSum(OmsInventoryDTO dto) {
        OmsInventoryVO omsInventoryVO = baseMapper.queryListSum(dto);
        return omsInventoryVO;
    }


    @Override
    public List<OmsInventoryVO> queryList(OmsInventoryDTO dto) {

        //排序字段名需要驼峰转数据库下划线类型字段名
        if (StrUtil.isNotEmpty(dto.getSortField())) {
            dto.setSortField(CommonUtil.camel2Underline(dto.getSortField()));
        }
        List<OmsInventoryVO> omsInventoryVOList = baseMapper.queryList(dto);
        omsInventoryVOList.forEach(r->{
            r.setQuantityAvailable(r.getQuantity().subtract(r.getContUseQuantity()).subtract(r.getUseQuantity()) );
            //r.setWarehouseName(warehouseCache.translate(r.getWarehouseCode()));
                }
        );
        return omsInventoryVOList;
    }

    @Override
    public List<Map<String, Object>> inventoryCount(String shipmentCode, List<String> warehouseCodes) {
        return baseMapper.inventoryCount(shipmentCode, warehouseCodes) ;
    }

    /**
     * 释放占用库存
     * @param warehouseCode
     * @param goodsCode
     * @param shipmentCode
     * @param lockQuantity
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void releaseOccupiedInventory(String warehouseCode, String goodsCode,  String shipmentCode, BigDecimal lockQuantity){
        // 增加占用数量， 数量条件是 总数量 >= 原占用数量 + 不可用数量 + 新占用数量
         this.update(new UpdateWrapper<OmsInventory>().lambda().eq(OmsInventory::getWarehouseCode, warehouseCode)
                .eq(OmsInventory::getGoodsCode, goodsCode).eq(OmsInventory::getShipmentCode, shipmentCode)
                .apply(" use_quantity >= " + lockQuantity)
                .setSql(" use_quantity = use_quantity + " + lockQuantity.negate()));
    }
}
